
package chatsystem.ni;

import chatsystem.util.Pair;
import chatsystemTDa2.Message;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/** Inclut le socket multicast, synchronisation et sérialisation. */
public class Socket {

   public Socket(InetAddress destGroup, int port) throws IOException
   {
      _local = InetAddress.getLocalHost();
      _bcast = InetAddress.getByName("255.255.255.255");

      _port = port;
      // bind sur l'addresse localhost plutôt que sur INADDR_ANY ->
      // répare l'appli sur les Windows mal configurés de l'INSA (cartes réseaux
      // virtuelles), mais la casse sous linux -> désactivé.
      //_sock = new DatagramSocket(new InetSocketAddress(_local, port));
      _sock = new DatagramSocket(port);
      // pas de multicast, finalement.
      //_sock.joinGroup(destGroup);
      _sock.setBroadcast(true);

      _pkt = new DatagramPacket(new byte[2048], 2048);
      _wbuff = new ByteArrayOutputStream();

      System.out.println(_local);
   }

   public synchronized void sendTo(InetAddress to, Message m)
   {
      try {
         if (to.equals(InetAddress.getByName("255.255.255.255")))
            to = _bcast;

         //System.out.println(to);

         _wbuff.reset();
         ObjectOutputStream out = new ObjectOutputStream(_wbuff);
         out.writeObject(m);

         byte[] pl = _wbuff.toByteArray();
         DatagramPacket pkt = new DatagramPacket(pl, pl.length, to, _port);
         _sock.send(pkt);

      } catch (IOException ex) {
        ex.printStackTrace();
        System.exit(-1);
      }
   }
   
   /** Bloquant, mais l'attente s'arrête en exception si un autre thread 
    *  appelle close() */
   public Pair<InetAddress, Message> recvFrom() throws IOException, ClassNotFoundException
   {
      do {
         _sock.receive(_pkt);
         System.out.println(_pkt.getAddress());
      } while (_local.equals(_pkt.getAddress()));
            
      ByteArrayInputStream rbuff = new ByteArrayInputStream(_pkt.getData(), _pkt.getOffset(), _pkt.getLength());
      ObjectInputStream in = new ObjectInputStream(rbuff);
      
      return new Pair(_pkt.getAddress(), (Message)in.readObject());
   }
   
   public void close()
   {
      _sock.close();
   }
   
/*****************************************************************************/
   
   private DatagramSocket _sock;
   private InetAddress _local; // to filter out my own writings
   private InetAddress _bcast;
   private int _port;
   private DatagramPacket _pkt; // for receive only
   private ByteArrayOutputStream _wbuff;
}
